//-----------------------------------------------------------------------------
//
// Filename: SelfEditingModel.cs
//
// Description: Model that has functionality to update itself.
// 
// History:
// 03 Feb 2004	Aaron Clauson	Created.
// 04 Feb 2004	Aaron Clauson	Added Update method.
// 15 Feb 2004	Aaron Clauson	Adjusted so that model does not have to be /page/contents. Instead caller
//								can specify a root to work down from. For simple use default root can still be used.
//								Added authorisation functionality.
//
// License: 
// Public Domain.
//-----------------------------------------------------------------------------

using System;
using System.Collections;
using System.IO;
using System.Xml;
using MaverickLite.Config;
using MaverickLite.Security;

namespace MaverickLite.Aza.Model
{
	/// <summary>
	/// Model that has the ability to update itself.
	/// </summary>
	public class SelfEditingModel
	{	
		protected XmlDocument m_modelDom = new XmlDocument();		// The concrete model.
		protected string m_modelMetadataPath = null;				// The path to the physical xml model.
		
		/// <summary>
		/// Constructor needs to load the model.
		/// </summary>
		/// <param name="modelMetadata">Physical path for the  model.</param>
		public SelfEditingModel(string modelMetadataPath, Credentials credentials)
		{
			try
			{			
				MavAppState.logger.Debug("SelfEditingModel metadata path is " + modelMetadataPath + ".");
				
				if(!Authorise(credentials))
				{
					throw new UnauthorizedAccessException("Not authorised to create a self editing model for " + modelMetadataPath + ".");
				}
				
				m_modelDom.Load(modelMetadataPath);
				m_modelMetadataPath = modelMetadataPath;
			}
			catch(Exception excp)
			{
				MavAppState.logger.Error("Exception SelfEditingModel (constructor): " + excp.Message);
				throw excp;
			}
		}

		/// <summary>
		/// Constructor needs to set the model up from the model metadata.
		/// </summary>
		/// <param name="modelMetadata">Metadata about the model including the
		/// physical location access control etc.</param>
		public SelfEditingModel(XmlElement modelMetadata, Credentials credentials)
		{
			try
			{					
				if(!Authorise(credentials))
				{
					throw new UnauthorizedAccessException("Not authorised to create a self editing model.");
				}

				string physicalModelPath = modelMetadata.SelectSingleNode("physicalPath").InnerText;

				m_modelDom.Load(physicalModelPath);
				m_modelMetadataPath = physicalModelPath;
			}
			catch(Exception excp)
			{
				MavAppState.logger.Error("Exception SelfEditingModel (constructor): " + excp.Message);
				throw excp;
			}
		}

		private bool Authorise(Credentials credentials)
		{
			// Authorise the operation from the security section within the model.
			return true;
		}

		/// <summary>
		/// Returns a read only copy of the model to the caller.
		/// </summary>
		/// <returns>A string representation of the model xml dom.</returns>
		public XmlDocument GetModel()
		{
			if(m_modelDom.DocumentElement != null)
			{
				return m_modelDom;
			}
			else
			{
				return null;
			}
		}

		public bool Update(Hashtable data, Credentials credentials)
		{
			try
			{
				if(!Authorise(credentials))
				{
					throw new UnauthorizedAccessException("Not authorised to update self editing model.");
				}

				bool updated = false;		// Indicates whether the model has been updated or not.	
			
				// Iterate through each request data element to see if it indicates a node to be updated.
				foreach(DictionaryEntry dataItem in data)
				{
					XmlNode updateNode = this.m_modelDom.SelectSingleNode("//*[@id='" + dataItem.Key + "']");

					if(updateNode != null)
					{
						updateNode.InnerXml = (string)dataItem.Value;
						updated = true;
					}
				}

				if(updated)
				{
					this.m_modelDom.Save(m_modelMetadataPath);
				}
			
				return true;
			}
			catch(ApplicationException appExcp)
			{
				throw appExcp;
			}
			catch(Exception excp)
			{
				MavAppState.logger.Error("Exception SelfEditingModel (Update): " + excp.Message);
				throw excp;
			}
		}


		public void Add(string nodeName, string nodeContents, Credentials credentials)
		{
			try
			{
				if(!Authorise(credentials))
				{
					throw new UnauthorizedAccessException("Not authorised to append to self editing model.");
				}
			
				if(nodeName == null || nodeName.Trim() == String.Empty)
				{
					throw new ApplicationException("No name was supplied when attemtping to add a new node.");
				}

				XmlElement appendEntry = m_modelDom.CreateElement(nodeName);
				appendEntry.InnerXml = nodeContents;

				m_modelDom.SelectSingleNode("/page/contents").AppendChild(appendEntry);

				m_modelDom.Save(m_modelMetadataPath);
			}
			catch(Exception excp)
			{
				MavAppState.logger.Error("Exception SelfEditingModel (Add): " + excp.Message);
				throw excp;
			}
		}
	}
}
